import {
  Component,
  requireResource,
  resourcesList,
} from "../../../component";
import path from "path";
import fs from "fs";
import { ComponentInfo } from "./ComponentInfo";
import { DistStruct } from "./CreateDist";
import * as cheerio from "cheerio";

export class RunComponent {
  private module: Component<
    cheerio.Root,
    cheerio.Cheerio
  // DescCompoundType<cheerio.Root, cheerio.Cheerio>
  >;
  private moduleId: number;
  private ci: ComponentInfo;
  private dist: DistStruct;
  private newMark: string = "";
  private $: cheerio.Root | null = null;

  //result:
  private root: cheerio.Cheerio;
  private styleArr: string[] = [];
  private jsArr: string[] = [];
  private requiredRes: resourcesList[] = [];

  //, DescCompoundType<cheerio.Root, cheerio.Cheerio>
  constructor(
    ci: ComponentInfo,
    module: Component<cheerio.Root, cheerio.Cheerio>,
    id: number,
    distStructure: DistStruct
  ) {
    this.ci = ci;
    this.module = module;
    this.moduleId = id;
    this.dist = distStructure;
    // this.requiredRes = this.handleResources(
    //   this.module.require ? this.module.require() : {}
    // );
    this.root = this.loadHTML(`#${this.module.getName()}`);
    this.styleArr = this.loadCss();
    this.jsArr = this.loadJs();
  }
  /**
   *  reassign component mark and return component
   * @param selector dom selector
   * @returns component html node
   */
  public loadHTML(selector: string) {
    const indexStr = fs
      .readFileSync(this.ci.getComponentIndexFilePath())
      .toString();

    this.$ = cheerio.load(indexStr);
    const node = this.$(selector);

    this.newMark = this.module.getName() + "_" + this.moduleId;
    if (selector.startsWith("#")) node.attr("id", this.newMark);
    else {
      const clazz = node.attr("class");
      clazz
        ? node.attr("class", clazz + " " + this.newMark)
        : node.attr("class", this.newMark);
    }

    return node;
  }
  /**
   * reassign component css mark and return css file string
   * @returns css array
   */
  public loadCss() {
    const cssArr = this.module.getCss ? this.module.getCss() : [];
    const stylesheet: string[] = [];
    cssArr.forEach((val) => {
      const cs =
        val.type === "file"
          ? fs
            .readFileSync(
              path.join(this.ci.getComponentRootFolderPath(), val.path)
            )
            .toString()
          : (this.$ && this.$(val.selector).text()) || "";
      stylesheet.push(this.alterCssMark(cs));
    });

    return stylesheet;
  }
  private alterCssMark(css: string) {
    const clazzMark = css.indexOf(".");
    const idMark = css.indexOf("#");
    const type = clazzMark > idMark ? "#" : ".";
    css = css.replace(
      `${type}${this.module.getName()}`,
      `${type}${this.newMark}`
    );
    return css;
  }
  public loadJs() {
    const jsArr = this.module.getJs ? this.module.getJs() : [];
    const js: string[] = [];
    jsArr.forEach((val) => {
      const jsFile =
        val.type === "file"
          ? fs
            .readFileSync(
              path.join(this.ci.getComponentRootFolderPath(), val.path)
            )
            .toString()
          : (this.$ && this.$(val.selector).text()) || "";

      js.push(jsFile);
    });

    return js;
  }
  public handleResources(resList: requireResource) {
    // if (!fs.existsSync(this.dist.getImgFolderPath())) return resList;
    // const resList = this.module.require ? this.module.require() : {};
    let index = fs.readdirSync(this.dist.getImgFolderPath()).length + 1;
    const newList: resourcesList[] = [];
    for (const key in resList) {
      const element = resList[key];

      const from = path.join(this.ci.getComponentRootFolderPath(), element);
      const to = path.join(
        this.dist.getImgFolderPath(),
        index + path.extname(element)
      );

      fs.copyFileSync(from, to);

      newList.push({
        before: {
          name: key,
          val: resList[key],
        },
        after: {
          name: this.getModuleId() + key,
          val: path.relative(this.dist.getRootPath(), to),
        },
      });
      // newList[this.getModuleId() + key] = path.relative(
      //   this.dist.getRootPath(),
      //   to
      // );

      index++;
    }

    this.requiredRes = newList;
    // return resList;
  }

  public setRequiredRes(list: resourcesList[]) {
    this.requiredRes = list;
  }

  public getJs() {
    return this.jsArr;
  }
  public getCss() {
    return this.styleArr;
  }
  public getDom() {
    return this.root;
  }
  public getModuleId() {
    // return this.moduleId;
    return this.newMark;
  }
  public getResourceList() {
    return this.requiredRes;
  }
  public getModule() {
    return this.module;
  }
}
